package promote.brozen.netty.jav.nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

/**
 * @author Brozen
 * @date 2020/9/27 8:56 AM
 * @email brozen@qq.com
 */
public class NioServerReactor extends SelectorReactor {

    public NioServerReactor(Selector selector) throws IOException {
        super(selector);
        selectCallback = (key, selectableChannel) -> {
            try {
                // 可以接受连接
                if (key.isAcceptable()) {
                    // select就绪时，从ServerSocketChannel中接收一个SocketChannel
                    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectableChannel;
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);
                    System.out.println("客户端接入：" + socketChannel);

                    // 注册到多路复用器
                    socketChannel.register(selector, SelectionKey.OP_READ, this);
                }

                // 连接中有数据就绪
                if (key.isReadable()) {
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    onSocketChannelReady(key, socketChannel);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        };
    }


    private void onSocketChannelReady(SelectionKey key, SocketChannel socketChannel) {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        try {
            // 读取数据到缓冲区
            int readBytes = socketChannel.read(buffer);

            // 已读数据长度为-1，则通道已关闭
            if (readBytes < 0) {
                socketChannel.close();
                key.cancel();
            } else if (readBytes > 0) {
                // 已读数据长度>0，则有数据
                readSocketChannel(socketChannel, buffer, readBytes);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void readSocketChannel(SocketChannel socketChannel, ByteBuffer buffer, int readBytes) {
        // 先重置读取位置
        buffer.flip();

        // 读出数据
        byte[] data = new byte[buffer.remaining()];
        buffer.get(data);

        // 转字符串
        String msg = new String(data);
        System.out.println("ServerReceive: " + msg);

        // 发送反馈
        responseSocketChannel(socketChannel, "ECHO: " + msg);
    }

    private void responseSocketChannel(SocketChannel socketChannel, String msg) {
        try {
            // 先拿到二进制数据
            byte[] data = msg.getBytes();

            // 写入Buffer
            ByteBuffer buffer = ByteBuffer.allocate(data.length);
            buffer.put(data);
            buffer.flip();

            // 发送给客户端
            socketChannel.write(buffer);
        } catch (IOException e) {
            System.out.println("写入客户端数据失败");
            e.printStackTrace();
        }
    }
}
